package com.dailyblue.java.project.bookstore.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dailyblue.java.project.bookstore.bean.User;
import com.dailyblue.java.project.bookstore.exception.ErrorPasswordException;
import com.dailyblue.java.project.bookstore.exception.NotFoundUsernameException;
import com.dailyblue.java.project.bookstore.mapper.UserMapper;
import com.dailyblue.java.project.bookstore.service.UserService;
import com.dailyblue.java.project.bookstore.util.JsonResult;
import com.dailyblue.java.project.bookstore.util.JwtConfig;
import com.dailyblue.java.project.bookstore.util.ResultCode;
import com.dailyblue.java.project.bookstore.util.ResultTool;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.security.MD5Encoder;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    private static final String ALL_USER_KEY = "ALL_USER_KEY";
    private static final String PREFIX_USER_KEY = "USER::";
    private static final String ALL_USER_COUNT = "ALL_USER_COUNT";

    @Override
    public JsonResult find(int page, int size) {
        log.info("获取第{}页数据，每页显示{}条", page, size);
        // 判断redis中是否存在数据
        // 对象存放到values中
        ValueOperations<String, String> values = stringRedisTemplate.opsForValue();
        // 集合存放到lists中
        ListOperations<String, String> lists = stringRedisTemplate.opsForList();
        // 集合是否存在
        List<String> allKey = lists.range(ALL_USER_KEY, 0, -1);
        if (allKey == null || allKey.size() == 0) {
            log.info("第一次访问");
            // 说明从来没有缓存过数据
            // 从数据库中获取数据
            PageHelper.startPage(page, size);
            List<User> list = list();
            PageInfo<User> pageInfo = new PageInfo<>(list);
            // 缓存
            // 填充
            for (int i = 0; i < pageInfo.getTotal(); i++) {
                lists.rightPush(ALL_USER_KEY, "null");
            }
            // 设置当前页数据
            int index = (page - 1) * size;
            for (User user : list) {
                String json = JSONArray.toJSONString(user);
                lists.set(ALL_USER_KEY, index, PREFIX_USER_KEY + user.getId());
                values.set(PREFIX_USER_KEY + user.getId(), json, 1, TimeUnit.DAYS);
                index++;
            }
            values.set(ALL_USER_COUNT, pageInfo.getTotal() + "");
            return ResultTool.success(pageInfo);
        }
        int begin = (page - 1) * size;
        String firstKey = allKey.get(begin);
        log.info("判断{}页是否存在，begin:{},firstKey:{}", page, begin, firstKey);
        // 1. 存在
        if (!firstKey.equals("null")) {
            int total = Integer.parseInt(values.get(ALL_USER_COUNT));

            log.info("存在");
            List<User> list = new ArrayList<>();
            int m = Math.min(total - begin, size);
            for (int i = begin; i < begin + m; i++) {
                String key = allKey.get(i);
                String jsonObj = values.get(key);
                User user = JSONArray.parseObject(jsonObj, User.class);
                list.add(user);
            }
            PageInfo<User> pageInfo = new PageInfo<>(list);
            pageInfo.setTotal(total);
            pageInfo.setPageNum(page);
            pageInfo.setPageSize(size);
            return ResultTool.success(pageInfo);
        }
        log.info("bu存在");
        // 2. 不存在
        // 从数据库中获取数据
        PageHelper.startPage(page, size);
        List<User> list = list();
        PageInfo<User> pageInfo = new PageInfo<>(list);
        // 存放到redis中
        int index = (page - 1) * size;
        for (User user : list) {
            log.info("开始替换null元素，从:{}开始", index);
            String json = JSONArray.toJSONString(user);
            lists.set(ALL_USER_KEY, index, PREFIX_USER_KEY + user.getId());
            values.set(PREFIX_USER_KEY + user.getId(), json, 1, TimeUnit.DAYS);
            index++;
        }
        return ResultTool.success(pageInfo);
    }

    @Override
    public JsonResult find(String name, int page, int size) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.like("username", name);
        PageHelper.startPage(page, size);
        List<User> list = list(wrapper);
        PageInfo<User> pageInfo = new PageInfo<>(list);
        return ResultTool.success(pageInfo);
    }

    @Override
    public JsonResult updatePassword(long id) {
        getBaseMapper().updatePassword(id);
        return ResultTool.success();
    }

    @Override
    public JsonResult deleteUser(String id) {
        boolean flag = removeById(id);
        if (flag) {
            // 更新缓存
            ValueOperations<String, String> values = stringRedisTemplate.opsForValue();
            ListOperations<String, String> lists = stringRedisTemplate.opsForList();
            values.getAndDelete(PREFIX_USER_KEY + id);
            log.info("开始更新缓存，key:{}", PREFIX_USER_KEY + id);
            lists.remove(ALL_USER_KEY, 1, PREFIX_USER_KEY + id);
            long count = Integer.parseInt(values.get(ALL_USER_COUNT));
            count--;
            values.set(ALL_USER_COUNT, count + "");
        }
        return ResultTool.success();
    }

    @Override
    public JsonResult disableUser(String id, int state) {
        UpdateWrapper<User> wrapper = new UpdateWrapper();
        wrapper.set("state", state);
        wrapper.eq("id", id);
        boolean flag = update(wrapper);
        if (flag) {
            ValueOperations<String, String> values = stringRedisTemplate.opsForValue();
            String str = values.get(PREFIX_USER_KEY + id);
            User user = JSONArray.parseObject(str, User.class);
            user.setState(state);
            values.set(PREFIX_USER_KEY + id, JSONArray.toJSONString(user));
        }
        return ResultTool.success();
    }

    @Override
    public JsonResult updateUser(User user) {
        UpdateWrapper<User> wrapper = new UpdateWrapper<>();
        wrapper.set("username", user.getUsername());
        wrapper.set("phone", user.getPhone());
        wrapper.set("email", user.getEmail());
        wrapper.set("address", user.getAddress());
        wrapper.eq("id", user.getId());
        boolean flag = update(wrapper);
        if (flag) {
            ValueOperations<String, String> values = stringRedisTemplate.opsForValue();
            String str = values.get(PREFIX_USER_KEY + user.getId());
            User user1 = JSONArray.parseObject(str, User.class);
            user1.setAddress(user.getAddress());
            user1.setEmail(user.getEmail());
            user1.setPhone(user.getPhone());
            user1.setUsername(user.getUsername());
            values.set(PREFIX_USER_KEY + user.getId(), JSONArray.toJSONString(user1));
        }
        return ResultTool.success();
    }

    @SneakyThrows
    public JsonResult login(User user) {
        // 1⃣️ 校验账号是否存在
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("username", user.getUsername());
        // 验证后台登陆1或者前台登陆0
        wrapper.eq("is_admin", user.getIsAdmin());
        User user1 = this.getOne(wrapper);
        if (user1 == null) {
            throw new NotFoundUsernameException("账号不存在！");
        }
        // 2⃣️ 校验密码是否正确
        MessageDigest md = MessageDigest.getInstance("md5");
        String password1 = MD5Encoder.encode(md.digest(user.getPassword().getBytes()));
        String password2 = user1.getPassword();
        if (!password1.equals(password2)) {
            throw new ErrorPasswordException("密码错误！");
        }
        // 3⃣️ 生成 token 字符串
        String token = JwtConfig.getJwtToken(user1);
        // 4⃣️ 保存到 redis 中
        ValueOperations<String, String> values = stringRedisTemplate.opsForValue();
        values.set("token:" + user1.getId(), token, 1, TimeUnit.DAYS);
        // 5⃣️ 返回给浏览器
        JsonResult result = ResultTool.success(token);
        result.setErrorMsg(user1.getUsername());
        return result;
    }
}
